package com.echatim.service.app;

import com.annotation.MethodFor;
import com.annotation.TopicFor;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.broker.base.protocol.response.Resp;
import com.commom.AppRespError;
import com.commom.DBConst;
import com.commom.Topic;
import com.echatim.dto.RoomDetailListDTO;
import com.echatim.dto.RoomGetDTO;
import com.echatim.dto.RoomListDTO;
import com.echatim.dto.UserListDTO;
import com.echatim.entity.Room;
import com.echatim.entity.RoomUser;
import com.echatim.entity.User;
import com.echatim.form.*;
import com.echatim.mapper.RoomMapper;
import com.utils.Beans;
import com.utils.Streams;
import com.utils.UUIDUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.validation.Valid;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author kong <androidsimu@163.com>
 * create by 2019/2/21 13:21
 * Description: echatim
 **/


@Slf4j
@TopicFor(value = Topic.APP_ROOM.name)
@Service
public class RoomService extends ServiceImpl<RoomMapper, Room>  {
    @Autowired
    private UserService userService;
    @Autowired
    private RoomUserService roomUserService;

    @Transactional
    @MethodFor(value = Topic.APP_ROOM.METHOD.ADD, consumer = RoomAddForm.class)
    public Resp<Long> add(@Valid RoomAddForm roomAddForm){
        log.info(" add: " + Beans.json(roomAddForm));
        // TODO: get sdkid from jwt
        String appKey = "";

        List<String> members = roomAddForm.getMembers();
        members.add(roomAddForm.getOwner()); // 添加群主
        // 检测 members, owner 的有效性
        List<User> users = userService.lambdaQuery().in(User::getAuid, members).list();
        List<String> memberNotExist = new ArrayList<>();
        members.forEach(v->{
            if(!Streams.map(users, vv->vv.getAuid()).contains(v)){
                memberNotExist.add(v);
            }
        });
        if(!memberNotExist.isEmpty()){
            return Resp.failed("以下的群员不存在:" + Beans.json(memberNotExist), AppRespError.ROOM_MEMBER_NOT_EXIST.getCode());
        }
        // 添加群
        Room room = Beans.copy(roomAddForm, Room.class)
                .setUid(UUIDUtils.gen())
                .setAppKey(appKey)
                .setCreateTime(new Date());
        this.save(room);
        // 添加群员
        addRoomUserToDB(appKey, room.getId(), members);

        return Resp.ok(room.getId());
    }
    @MethodFor(value = Topic.APP_ROOM.METHOD.UPDATE, consumer = RoomUpdateForm.class)
    public Resp<String> updateRoom(RoomUpdateForm updateForm) {
        this.lambdaUpdate()
                .set(Beans.strNotEmpty(updateForm.getName()), Room::getName, updateForm.getName())
//                .set(Beans.strNotEmpty(updateForm.getOwner()), Room::getOwner, updateForm.getOwner())
                .set(Beans.strNotEmpty(updateForm.getAnnounce()), Room::getAnnounce, updateForm.getAnnounce())
                .set(Beans.strNotEmpty(updateForm.getIntroduce()), Room::getIntroduce, updateForm.getIntroduce())
                .set(Beans.strNotEmpty(updateForm.getAvatar()), Room::getAvatar, updateForm.getAvatar())
                .set(Beans.strNotEmpty(updateForm.getConfJoinmode()), Room::getConfJoinmode, updateForm.getConfJoinmode())
                .set(Beans.strNotEmpty(updateForm.getConfBeinvite()), Room::getConfJoinmode, updateForm.getConfBeinvite())
                .set(Beans.strNotEmpty(updateForm.getConfInviteother()), Room::getConfInviteother, updateForm.getConfInviteother())
                .set(Beans.strNotEmpty(updateForm.getConfUpdate()), Room::getConfUpdate, updateForm.getConfUpdate())
                .set(Room::getMaxMember, updateForm.getMaxMember())
                // where
                .eq(Room::getId, updateForm.getRid())
                .update();

        return Resp.ok("更新成功");
    }
    @MethodFor(value = Topic.APP_ROOM.METHOD.LIST, consumer = RoomListForm.class)
    public Resp<List<RoomListDTO>> listRoom(RoomListForm roomListForm) {
        List<Room> users = this.lambdaQuery().in(Room::getId, roomListForm.getRids()).list();
        return Resp.ok(Streams.map(users, v->Beans.copy(v, RoomListDTO.class).setRid(v.getId())));
    }

    @MethodFor(value = Topic.APP_ROOM.METHOD.GET, consumer = RoomGetForm.class)
    public Resp<RoomGetDTO> getRoom(RoomGetForm getForm) {
        Room room = this.lambdaQuery().eq(Room::getId, getForm.getRid()).one();
        if(room == null){
            return Resp.failed("无法找到群,rid = " + getForm.getRid(), AppRespError.ROOM_NOT_FOUND.getCode());
        }
        RoomGetDTO dto = Beans.copy(room, RoomGetDTO.class);
        dto.setRid(room.getId());
        return Resp.ok(dto);
    }

    @MethodFor(value = Topic.APP_ROOM.METHOD.ADD_USER, consumer = RoomAddUserForm.class)
    public Resp<String> addRoomUser(RoomAddUserForm addUserForm) {
        String sdkId = "";
        addRoomUserToDB(sdkId, addUserForm.getRid(), addUserForm.getMembers());
        return Resp.ok("成功.");
    }

    private void addRoomUserToDB(String sdkId, Long roomId, List<String> members){
        // 添加群员(TODO: BUG.群员会重复添加)
        List<RoomUser> roomUsers = members.stream()
                .map(v->{
                    return new RoomUser()
                            .setUid(UUIDUtils.gen())
                            .setRid(roomId)
                            .setAuid(v)
                            .setAppKey(sdkId)
                            .setStatus(DBConst.EntryStatus.NORMAL.name())
                            .setCreateTime(new Date());
                }).collect(Collectors.toList());
        roomUserService.saveBatch(roomUsers);
    }

    @MethodFor(value = Topic.APP_ROOM.METHOD.DEL_USER, consumer = RoomDelUserForm.class)
    public Resp<String> delRoomUser(RoomDelUserForm delUserForm) {
        // TODO: check is the room's master?
        delRoomUserFromDB(delUserForm.getMembers());
        return Resp.ok("成功.");
    }


    private void delRoomUserFromDB(List<String> members){
        List<RoomUser> roomUsers = roomUserService.lambdaQuery().in(RoomUser::getAuid, members).list();
        roomUserService.removeByIds(Streams.ids(roomUsers, v->v.getId()));
    }

    @MethodFor(value = Topic.APP_ROOM.METHOD.DEL, consumer = RoomDelForm.class)
    public Resp<String> delRoom(RoomDelForm delForm) {
        int cnt = this.lambdaQuery()
                .eq(Room::getId, delForm.getRid())
                .eq(Room::getOwner, delForm.getOwner())
                .count();
        if(cnt == 0){
            return Resp.failed(String.format("owner:%s 不是群:%d 的群主", delForm.getOwner(), delForm.getRid()), AppRespError.ROOM_OWNER_NOT_MASTER.getCode());
        }
        // 标记删除
        this.lambdaUpdate()
                .set(Room::getStatus, DBConst.EntryStatus.DEL.name())
                .eq(Room::getId, delForm.getRid())
                .update();
        // 删组员
        List<RoomUser> roomUsers = roomUserService.lambdaQuery().in(RoomUser::getRid, delForm.getRid()).list();
        roomUserService.removeByIds(Streams.ids(roomUsers, v->v.getId()));

        return Resp.ok("成功.");
    }

    @MethodFor(value = Topic.APP_ROOM.METHOD.LIST_JOIN, consumer = RoomListJoinForm.class)
    public Resp<List<RoomListDTO>> listRoomJoin(RoomListJoinForm roomListJoinForm) {
        List<RoomUser> roomUsers = roomUserService.lambdaQuery()
                .eq(RoomUser::getAuid, roomListJoinForm.getAuid())
                .list();
        if(roomUsers.isEmpty()){
            return Resp.ok(Collections.emptyList());
        }
        List<Long> rids = Streams.ids(roomUsers, v->v.getRid());
        return this.listRoom(new RoomListForm().setRids(rids));
    }

    @MethodFor(value = Topic.APP_ROOM.METHOD.LIST_MEMBER, consumer = RoomListForm.class)
    public Resp<List<RoomDetailListDTO>> listRoomDetail(RoomListForm roomListForm) {
        List<Room> rooms = this.lambdaQuery().in(Room::getId, roomListForm.getRids()).list();
        List<RoomUser> roomUsers = roomUserService.lambdaQuery()
                .in(RoomUser::getRid, Streams.ids(rooms, v->v.getId()))
                .list();
        if(roomUsers.isEmpty()){
            return Resp.ok(null);
        }
        List<User> users = userService.lambdaQuery()
                .in(User::getAuid, Streams.keys(roomUsers, v->v.getAuid()))
                .list();
        Map<String, UserListDTO> userMapByAuid = Streams.toMapByKey(
                Streams.map(users, v->Beans.copy(v, UserListDTO.class)), v->v.getAuid()
        );

//        Map<Integer, List<RoomUser>> roomUsersMapByGid = Streams.groupById(roomUsers, v->v.getRid());
        List<RoomDetailListDTO> dtos = new ArrayList<>();
        rooms.forEach(v->{
            RoomDetailListDTO dto = Beans.copy(v, RoomDetailListDTO.class);
            dto.setMembers(
                    roomUsers.stream()
                    .map(vv->userMapByAuid.getOrDefault(vv.getAuid(), new UserListDTO()))
                    .collect(Collectors.toList())
            );
            dtos.add(dto);
        });

        return Resp.ok(dtos);
    }


}
